using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;

using Peradigm.Framework.Domain.Parties;
using Peradigm.Framework.Persistence;

using Liberty.Domain.ApplicationManagement;
using Liberty.Domain.CaseManagement;
using Liberty.Domain.GrantManagement;
using Liberty.Domain.ApprovalManagement;
using Liberty.Domain.NoteManagement;


namespace Liberty.Domain.ServiceMemberManagement
{
    [Serializable]
    public class ServiceMember : Applicant, INotable
    {
        #region Constants
        private const int 
            FIRST_MATCH = 0;
        public const string
            CURRENT_ADDRESS = TypeOfContactPoint.DESCRIPTOR_PRIMARY,
            HOME_OF_RECORD_ADDRESS = TypeOfContactPoint.DESCRIPTOR_SECONDARY,
            PRIMARY_PHONE_NUMBER = TypeOfContactPoint.DESCRIPTOR_PRIMARY,
            SECONDARY_PHONE_NUMBER = TypeOfContactPoint.DESCRIPTOR_SECONDARY;
        #endregion

        #region Event Handlers
        #endregion

        #region Methods
        public ServiceMember AddCase( Case newCase )
        {
            if( !this.primCases.Contains( newCase ) )
            {
                this.primCases.Add( newCase );
            }

            if( newCase.ServiceMember != null && newCase.ServiceMember != this )
            {
                newCase.ServiceMember.RemoveCase( newCase );
            }
            newCase.ServiceMember = this;

            return this;
        }

        public Note AddNote( Note newNote )
        {
            if( false == this.primNotes.Contains( newNote ) )
            {
                this.primNotes.Add( newNote );
            }
            
            return newNote;
        }

        public Case RemoveCase( Case existingCase )
        {
            if( this.primCases.Contains( existingCase ) )
            {
                this.primCases.Remove( existingCase );
            }
            return existingCase;
        }

        public void RemoveNotes()
        {
            this.primNotes.Clear();
        }

        public void RemoveCases()
        {
            this.primCases.Clear();
        }
        #endregion

        #region Properties
        public DateTime? BornOn
        {
            get
            {
                if( i_BornOn.HasValue )
                {
                    return i_BornOn.Value;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                if( value.HasValue )
                {
                    i_BornOn = value;
                }
                else
                {
                    i_BornOn = null;
                }
            }
        }

        public Branch Branch
        {
            get
            {
                if( null != this.Rank )
                {
                    return this.Rank.BranchOfService;                    
                }
                else
                {
                    return null;
                }
            }
        }

        public Liberty.Domain.Kernel.Address CurrentAddress
        {
            get
            {
                return (Liberty.Domain.Kernel.Address)this.AddressFor( ServiceMember.CURRENT_ADDRESS );
            }
            set
            {
                this.AddAddress( ServiceMember.CURRENT_ADDRESS, value );
            }
        }

        public IEnumerable<Case> Cases
        {
            get
            {
                return this.primCases;
            }
        }

        public Liberty.Domain.Kernel.Address HomeOfRecord
        {
            get
            {
                return (Liberty.Domain.Kernel.Address)this.AddressFor( ServiceMember.HOME_OF_RECORD_ADDRESS );
            }
            set
            {
                this.AddAddress( ServiceMember.HOME_OF_RECORD_ADDRESS, value );
            }
        }

        public Rank Rank
        {
            get
            {
                return i_Rank;
            }
            set
            {
                i_Rank = value;
            }
        }

        public Unit UnitAssignment
        {
            get
            {
                return i_UnitAssignment;
            }
            set
            {
                i_UnitAssignment = value;
            }
        }

        public IEnumerable<Note> Notes
        {
            get
            {
                return this.primNotes;
            }
        }

        public IEnumerable<Event> Events
        {
            get
            {
                return this.primEvents;
            }
        }

        public IEnumerable<Grant> Grants
        {
            get
            {
                List<Grant> grants = new List<Grant>();
                foreach( Case aCase in this.Cases )
                {
                    grants.AddRange( aCase.Grants );
                }

                return grants;
            }
        }
        #endregion

        #region Private Methods
        #endregion

        #region Private Properties
        private List<Case> primCases
        {
            get
            {
                return i_Cases;
            }
            set
            {
                i_Cases = value;
            }
        }

        private List<Note> primNotes
        {
            get
            {
                return i_Notes;
            }
            set
            {
                i_Notes = value;
            }
        }

        private List<Event> primEvents
        {
            get
            {
                return i_Events;
            }
            set
            {
                i_Events = value;
            }
        }	
        #endregion

        #region Construction and Finalization
        /// <summary>
        /// Creates a stubbed service member populated with frequently used primitives.
        /// Other aggregated objects are not populated by this factory method.
        /// </summary>
        /// <returns></returns>
        public static new ServiceMember TestInstance()
        {
            ServiceMember testServiceMember = new ServiceMember( 1L, PersistentModel.NEW_VERSION,
               "Major",
               "Pain",
               new DateTime( 1968, 12, 6 ),
               Rank.TestInstance(),
               Unit.TestInstance() );
            return testServiceMember;

        }
        
        public ServiceMember()
            : base( PersistentModel.NEW_OID, PersistentModel.NEW_VERSION, string.Empty, string.Empty )
        {
        }

        public ServiceMember( long oid, byte[] version, string firstName, string lastName,
                                DateTime dateOfBirth, Rank rank, Unit unitAssignment )
            : base( oid, version, firstName, lastName )
        {
            this.BornOn = dateOfBirth;
            this.Rank = rank;
            this.UnitAssignment = unitAssignment;
        }
        #endregion

        #region Data Elements
        private DateTime? i_BornOn;
        private List<Case> i_Cases = new List<Case>();
        private Rank i_Rank;
        private Unit i_UnitAssignment = new Unit( string.Empty );
        private List<Note> i_Notes = new List<Note>();
        private List<Event> i_Events = new List<Event>();
        #endregion
    }
}